<template>
    <div
      ref="svgColor"
      style="width: 100%; height: 100%">
      <svg
        :width="svgWidth"
        :height="svgHeight"
        :viewBox="`0 0 ${svgWidth} ${svgHeight}`"
        style="display: block">
        <!-- 渐变定义 -->
        <defs>
          <linearGradient
            :id="gradientId"
            x1="0"
            y1="1"
            x2="0"
            y2="0">
            <stop
              v-for="stop in colorStops"
              :key="stop.offset"
              :offset="stop.offset"
              :stop-color="stop.color" />
          </linearGradient>
        </defs>
        <!-- 色柱 -->
        <rect
          :x="barX"
          :y="barY"
          :width="barWidth"
          :height="barHeight"
          :fill="`url(#${gradientId})`"
          stroke="black" />
        <!-- 刻度线和标签 -->
        <g
          v-for="(tick, i) in tickList"
          :key="i">
          <line
            :x1="barX + barWidth"
            :y1="tick.y"
            :x2="barX + barWidth + 5"
            :y2="tick.y"
            stroke="black"
            stroke-width="1" />
          <text
            :x="barX + barWidth + 12"
            :y="tick.y + fontSize / 3"
            :font-size="fontSize"
            fill="black"
            text-anchor="start">
            {{ tick.label }}
          </text>
        </g>
        <text
          :x="barX"
          :y="barY - 10"
          :font-size="fontSize * 0.8"
          fill="#000"
          style="font-weight: bold !important"
          text-anchor="start">
          {{ xUnit }}
        </text>
      </svg>
    </div>
</template>
  
<script setup>
import { computed, onMounted, ref, nextTick, onBeforeUnmount } from 'vue'

const props = defineProps({
    colorStops: {
        // 渐变色数组，格式如 [{offset:0,color:'#000'},{offset:1,color:'#fff'}]
        type: Array,
        required: true
    },
    min: { type: Number, default: 0 }, // 刻度最小值
    max: { type: Number, default: 1 }, // 刻度最大值
    ticks: { type: Number, default: 5 }, // 刻度数量
    // fontSize: { type: Number, default: 14 }, // 文字大小
    bottomPadding: { type: Number, default: 10 }, // 底部留白
    xUnit: { type: String, default: '' } // 单位
})

const svgColor = ref(null)
const svgWidth = ref(100)
const svgHeight = ref(240)
const barWidth = 24
const barX = 8
const barY = 40
const barHeight = computed(() => svgHeight.value - barY - props.bottomPadding)
const gradientId = 'colorbar-gradient'

const tickList = computed(() => {
    const arr = []
    for (let i = 0; i < props.ticks; i++) {
        const ratio = i / (props.ticks - 1)
        const y = barY + barHeight.value - ratio * barHeight.value
        const value = props.min + (props.max - props.min) * ratio
        arr.push({
        y,
        label: value.toFixed(2)
        })
    }
    return arr
})

function handleResize() {
    if (svgColor.value) {
        svgWidth.value = svgColor.value.clientWidth || 100
        svgHeight.value = svgColor.value.clientHeight || 240
        const size = (svgHeight.value / 240) * 16
        if (size >= 16) {
        fontSize.value = 16
        } else if (size < 12) {
        fontSize.value = 12
        } else {
        fontSize.value = size
        }
    }
}
// 容器自适应
const fontSize = ref(16)
let resizeObserver = null
const debouncedResize = debounce(handleResize, 50)
onMounted(() => {
    nextTick(() => {
        handleResize()
        if (window.ResizeObserver) {
        resizeObserver = new ResizeObserver(() => debouncedResize())
        if (svgColor.value) {
            resizeObserver.observe(svgColor.value)
        }
        } else {
        window.addEventListener('resize', debouncedResize)
        }
    })
})

onBeforeUnmount(() => {
    if (resizeObserver && svgColor.value) {
        resizeObserver.unobserve(svgColor.value)
    }
    window.removeEventListener('resize', debouncedResize)
})

function debounce(fn, delay = 300) {
    let timer = null
    return function (...args) {
        // 先清除之前的定时器
        if (timer) {
        clearTimeout(timer)
        }
        timer = setTimeout(() => {
        fn.apply(this, args)
        }, delay)
    }
}
</script>
  